//
//  HWDataRequest.m
//  MinisoEshop
//
//  Created by 李含文 on 2020/7/29.
//  Copyright © 2020 ＾淡~忘￡°C. All rights reserved.
//

#import "HWDataRequest.h"
#import <AFNetworking.h>
#import <YYKit/YYKit.h>
@class HWDataRequest;
@class HWDataManage;

/// 可设置的默认请求
static NSDictionary *_HWDataManageHeader;
/// 内部添加请求头
static NSDictionary *_HWDataManageFixedHeader;

static dispatch_semaphore_t _hw_semaphore;

@interface HWDataRequest (FixedHeade)

@end

@implementation HWDataRequest (FixedHeade)

// MARK: 重点-内部设置固定请求头
+ (NSMutableDictionary *)setFixedHeader {
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    return dic;
}
@end

@implementation HWDataRequestModel

@end

//MARK: - 请求类逻辑
@interface HWDataManage : NSObject

@end

@implementation HWDataManage

+ (NSMutableDictionary *)getUnrestrictedRequestUrls {
    static NSMutableDictionary *_hwunrestrictedRequestURLSDIC;
    if (_hwunrestrictedRequestURLSDIC == nil) {
        _hwunrestrictedRequestURLSDIC = [NSMutableDictionary dictionary];
    }
    return _hwunrestrictedRequestURLSDIC;
}
//MARK: 管理请求数组 用于取消使用
+ (NSMutableDictionary *)getAllTasks {
    static NSMutableDictionary *_HWDataManage_requestTasks;
    if (!_HWDataManage_requestTasks) {
        _HWDataManage_requestTasks = [NSMutableDictionary dictionary];
    }
    return _HWDataManage_requestTasks;
}
//MARK: 暴露给外界设置请求头
+ (void)setDefaultHeader:(NSDictionary *)header {
    _HWDataManageHeader = header;
}
//MARK: 设置内部固定请求头
+ (void)setFixedHeader:(NSDictionary *)header {
    _HWDataManageFixedHeader = header;
}
//MARK: 让AFHTTPSessionManager成为单利
+ (AFHTTPSessionManager *)manager {
    [self setFixedHeader:[HWDataRequest setFixedHeader]];;
    static AFHTTPSessionManager *manager = nil;
    static dispatch_once_t predicate;
    dispatch_once(&predicate, ^{
        manager = [AFHTTPSessionManager manager];
        manager.operationQueue.maxConcurrentOperationCount = 5;
        [manager.requestSerializer willChangeValueForKey:@"timeoutInterval"];
        manager.requestSerializer.timeoutInterval = 20.f;
        [manager.requestSerializer didChangeValueForKey:@"timeoutInterval"];
        manager.responseSerializer.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"application/xml", @"text/xml",@"text/html", @"application/json",@"text/plain",nil];
        // 发送json格式数据的时候加上这两句
        manager.requestSerializer = [AFJSONRequestSerializer serializer];
        manager.responseSerializer = [AFJSONResponseSerializer serializer];
    });
    return manager;
}

////MARK: - 请求处理
+ (void)request:(HWDataRequest*)request
               success:(void (^_Nullable)(NSURLSessionDataTask * _Nullable task, id  _Nullable responseObject))success
               failure:(void (^_Nullable)(NSURLSessionDataTask * _Nullable task, NSString *_Nullable error))failure {
    __block BOOL isisDontLimi = request.isRestrict;
    if (isisDontLimi) {
        [self lock:^{ isisDontLimi = [self isDontLimit:request.url]; }];
    }
    AFHTTPSessionManager *manager = [self manager];
    // 创建会话管理者
    NSURLSessionDataTask * task = nil;
    NSMutableDictionary *headerDict = [self getDefaultHeader];
    if (request.header.allKeys.count) {
        [request.header enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
            if (key.length && obj != nil) {
                [headerDict setObject:obj forKey:key];
            }
        }];
    }
    
    NSString *currenturl = [self getURL:request.url];
    __weak __typeof(self) weakSelf = self;
    if (request.method == HWRequestTypeGet) {
        task = [manager GET:currenturl parameters:request.params headers:headerDict progress:^(NSProgress * _Nonnull uploadProgress) {
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            __strong __typeof(self) strongSelf = weakSelf;
            [strongSelf success:request task:task responseObject:responseObject success:success];
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            __strong __typeof(self) strongSelf = weakSelf;
            [strongSelf failure:request task:task error:error failure:failure];
        }];
    } else {
        task = [manager POST:currenturl parameters:request.params headers:headerDict progress:^(NSProgress * _Nonnull uploadProgress) {
        } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
            __strong __typeof(self) strongSelf = weakSelf;
            [strongSelf success:request task:task responseObject:responseObject success:success];
        } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
            __strong __typeof(self) strongSelf = weakSelf;
            [strongSelf failure:request task:task error:error failure:failure];
        }];
    }
    if (task && isisDontLimi) { // 如果是不被限制的url不会加入到 任务管理中去 保证任务管理的唯一性
        [self lock:^{ [[self getAllTasks] setValue:task forKey:request.url]; }];
    }
}
//MARK: 请求成功处理
+ (void)success:(HWDataRequest*)request
           task:(NSURLSessionDataTask *)task
 responseObject:(id)responseObject
        success:(void (^_Nullable)(NSURLSessionDataTask * _Nullable task, id  _Nullable responseObject))success {
    [self showinfo:task responseObject:responseObject error:nil];
    if (request.isRestrict)
        [self lock:^{ [[self getAllTasks] removeObjectForKey:request.url]; }];
    if (!success) return;;
    success(task, responseObject);
}

//MARK: - 请求失败处理
+ (void)failure:(HWDataRequest*)request
           task:(NSURLSessionDataTask *)task
          error:(NSError *)error
        failure:(void (^_Nullable)(NSURLSessionDataTask * _Nullable task, NSString *_Nullable error))failure {
    [self showinfo:task responseObject:nil error:error];
    if (request.isRestrict)
        [self lock:^{ [[self getAllTasks] removeObjectForKey:request.url]; }];
    if (!failure) return;
    if (error.code != -999)  // -999 已取消
        failure(task,@"请求失败");
}

//MARK: 获取默认请求头
+ (NSMutableDictionary *)getDefaultHeader {
    NSMutableDictionary *currentheader = [NSMutableDictionary dictionary];
    if (_HWDataManageFixedHeader.allKeys.count) {
        [_HWDataManageFixedHeader enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
            if (key.length && obj != nil) {
                [currentheader setObject:obj forKey:key];
            }
        }];
    } // 添加固定请求头
    if (_HWDataManageHeader.allKeys.count) {
        [_HWDataManageHeader enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
            if (key.length  && obj != nil) {
                [currentheader setObject:obj forKey:key];
            }
        }];
    } // 添加设置的默认请求头
    return currentheader;
}
// 判断是否不被限制
+ (BOOL)isDontLimit:(NSString *)url {
    NSMutableDictionary *dic = [self getUnrestrictedRequestUrls];
    if (![dic valueForKey:url]) {
        NSLog(@"被限制URL:%@", url);
        [self cancelRequestWithURL:url];
        return YES;
    }
    return NO;
}
// MARK: - 根据url取消单个请求
+ (void)cancelRequestWithURL:(NSString *)url {
    [self cancelRequestWithURL:url action:nil];
}
//MARK: 打印请求信息
+ (void)showinfo:(NSURLSessionDataTask *)task responseObject:(id)responseObject error:(NSError * __nullable)error {
#if DEBUG
    NSString *url = @"";
    NSString *header = @"";
    NSString *body = @"";
    NSString *content = @"";
    if (task.originalRequest.URL.absoluteString.length)
        url = [NSString stringWithFormat:@"请求路径:\n%@\n", task.originalRequest.URL.absoluteString];
    if (task.originalRequest.allHTTPHeaderFields.allKeys.count)
        header = [NSString stringWithFormat:@"请求头:\n%@\n", task.originalRequest.allHTTPHeaderFields];
    NSString *bodystr = [[NSString alloc] initWithData:task.originalRequest.HTTPBody encoding:(NSUTF8StringEncoding)];
    if (bodystr.length)
        body = [NSString stringWithFormat:@"请求参数:\n%@\n", bodystr];;
    if (error)
        content = [NSString stringWithFormat:@"失败信息:\n%@\n", error.description];
    if (responseObject)
        content = [NSString stringWithFormat:@"返回数据:\n%@\n", responseObject];
    NSLog(@"\n===========================请求%@=============================\n%@%@%@%@\n===============================================================", (error == nil)?@"成功":@"失败", url, header, body, content);
#endif
}
// MARK: 取消所有请求
+ (void)cancelAllRequest {
    [self lock:^{
        [[self manager].tasks makeObjectsPerformSelector:@selector(cancel)];
        [[self getAllTasks] removeAllObjects];
    }];
}
// MARK: 根据url取消单个请求
+ (void)cancelRequestWithURL:(NSString *)url action:(void(^)(BOOL tag))action {
    if (url.length == 0) { if (action) action(NO); return;}
    [self lock:^{
        NSURLSessionDataTask *task = [[self getAllTasks] valueForKey:url];
        if (task) {
            [task cancel];
            [[self getAllTasks] removeObjectForKey:url];
            if (action) action(YES);
        }
    }];
}
// MARK: - url拼接域名
+ (NSString *)getURL:(NSString *)url {
    NSString *currenturl = @"";
    if (![url containsString:@"http"]) {
        currenturl = [HW_BASE_URL stringByAppendingString:url];
    } else {
        currenturl = url;
    }
    return currenturl;
}

//MARK: - 加锁保证线程安全
+ (void)lock:(void(^)(void))action {
    if (!action) return;
    if (!_hw_semaphore) {
        _hw_semaphore = dispatch_semaphore_create(1);
    }
    dispatch_semaphore_signal(_hw_semaphore);
    action();
    dispatch_semaphore_wait(_hw_semaphore, DISPATCH_TIME_FOREVER);
}
@end


//MARK: - 请求类对外开放
@interface HWDataRequest()
/// 请求方式
@property (nonatomic, assign) HWRequestType private_method;

@end

@implementation HWDataRequest
// MARK: 外包设置请求头
+ (void)setDefaultHeader:(NSDictionary *)header {
    [HWDataManage setDefaultHeader:header];
}

// MARK: 取消所有请求
+ (void)cancelAllRequest {
    [HWDataManage cancelAllRequest];
}

// MARK: 根据url取消单个请求
+ (void)cancelRequestWithURL:(NSString *)url {
    [HWDataManage cancelRequestWithURL:url action:nil];
}

+ (void)postWithConfig:(void(^)(HWDataRequest *request))config
               success:(void(^)(HWDataRequestModel *requestModel))success
               failure:(void(^)(NSString *error))failure {
    [self requestWithConfig:^(HWDataRequest *request) {
        if (!config) return;
        request.private_method = HWRequestTypePost;
        config(request);
    } success:success failure:failure];
}

+ (void)gettWithConfig:(void(^)(HWDataRequest *request))config
               success:(void(^)(HWDataRequestModel *requestModel))success
               failure:(void(^)(NSString *error))failure {
    [self requestWithConfig:^(HWDataRequest *request) {
        if (!config) return;
        request.private_method = HWRequestTypeGet;
        config(request);
    } success:success failure:failure];
}

+ (void)requestWithConfig:(void(^)(HWDataRequest *request))config
                  success:(void(^)(HWDataRequestModel *requestModel))success
                  failure:(void(^)(NSString *error))failure {
    HWDataRequest *request = [[HWDataRequest alloc] init];
    request.isRestrict = HWDataManage_isOpenLimit;
    config?config(request):nil;
    if (HW_BASE_URL.length == 0) { failure(@"请设置域名"); return; }
    if (request.url.length == 0) { failure(@"请求url不能为空"); return; }
    NSLog(@"%@", [request modelToJSONObject]);
    [HWDataManage request:request success:^(NSURLSessionDataTask * _Nullable task, id  _Nullable responseObject) {
        if (!success) return;
        HWDataRequestModel *requestModel = [HWDataRequestModel modelWithJSON:responseObject];
        requestModel.url = task.response.URL.absoluteString;
        requestModel.HTTPBody = [[NSString alloc] initWithData:task.originalRequest.HTTPBody encoding:(NSUTF8StringEncoding)];
        requestModel.allHTTPHeaderFields = task.originalRequest.allHTTPHeaderFields;
        success(requestModel);
    } failure:^(NSURLSessionDataTask * _Nullable task, NSString * _Nullable error) {
        failure?failure(error):nil;
    }];
}

- (NSMutableDictionary *)params {
    if (!_params)
        _params = [NSMutableDictionary dictionary];
    return _params;
}

- (NSMutableDictionary *)header {
    if (!_header)
        _header = [NSMutableDictionary dictionary];
    return _header;
}

- (HWRequestType)method {
    return self.private_method;
}
@end

